#include "textureGen.h"

using namespace std;

// Constructor
textureGen::textureGen(int w, int h) {
    width = w;
    height = h;
}

// Destructor
textureGen::~textureGen() {
    delete[] texture;
}

// Methods - Private
int textureGen::readInt(ifstream& input) {
    char buffer[4];
    input.read(buffer, 4);
    return toInt(buffer);
}

short textureGen::readShort(ifstream& input) {
    char buffer[2];
    input.read(buffer, 2);
    return toShort(buffer);
}

int textureGen::toInt(const char* bytes) {
    return (int)(((unsigned char)bytes[3] << 24) |
                 ((unsigned char)bytes[2] << 16) |
                 ((unsigned char)bytes[1] << 8) |
                 ((unsigned char)bytes[0]));
}

short textureGen::toShort(const char* bytes) {
    return (short)(((unsigned char)bytes[1] << 8) |
                 ((unsigned char)bytes[0]));
}

// Methods - Public
int textureGen::getWidth() {
    return width;
}

int textureGen::getHeight(){
    return height;
}

unsigned char* textureGen::getTexture(){
    return texture;
}

void textureGen::readPPM(const char* fileName){
    FILE* fp;
    int i, w, h, d;
    char head[70];          // max line <= 70 in PPM (per spec).
    
    fp = fopen(fileName, "rb");
    if(!fp){
        printf("error opening file %s\n", fileName);
        return;
    }
    
    // grab first two chars of the file and make sure that it has the
	// correct magic cookie for a raw PPM file
    fgets(head, 70, fp);
    if(strncmp(head, "P6", 2)){
        printf("%s: not a raw PPM file\n", fileName);
        return;
    }
    
    // grab the three elements in the header (width, height, maxval).
    i = 0;
    while(i < 3) {
        fgets(head, 70, fp);
        if(head[0] == '#') continue;     // skip comments
        else if(i == 0) i += sscanf(head, "%d %d %d", &w, &h, &d);
        else if(i == 1) i += sscanf(head, "%d %d", &h, &d);
        else if(i == 2) i += sscanf(head, "%d", &d);
    }
    
    if(width != w || height != h){
        printf("width and height of file do not match that of texture\n");
        return;
    }
    
    // grab all the image data in one fell swoop. 
    texture = texture = new unsigned char[w*h*3];;
    fread(texture, sizeof(unsigned char), w*h*3, fp);
    fclose(fp);
}

void textureGen::readBMP(const char* fileName){
    ifstream input;
    int x, y, c, w, h;
    
	input.open(fileName, ifstream::binary);
    if(!input.is_open()){
        printf("error opening file %s\n", fileName);
        return;
    }
	char buffer[2];
	input.read(buffer, 2);
    if(strncmp(buffer, "BM", 2)){
        printf("%s: not a BMP file\n", fileName);
        return;
    }
	input.ignore(8);
	int dataOffset = readInt(input);
	
	//Read the header
	int headerSize = readInt(input);
	switch(headerSize) {
		case 40:
			//V3
			w = readInt(input);
			h = readInt(input);
			input.ignore(2);
            if(readShort(input) != 24) printf("Image is not 24 bits per pixel\n");
            if(readShort(input) != 0)  printf("Image is compressed\n");
			break;
		case 12:
			//OS/2 V1
			w = readShort(input);
			h = readShort(input);
			input.ignore(2);
			if(readShort(input) != 24) printf("Image is not 24 bits per pixel\n");
			break;
		case 64:
			//OS/2 V2
			printf("Can't load OS/2 V2 bitmaps\n");
			break;
		case 108:
			//Windows V4
			printf("Can't load Windows V4 bitmaps\n");
			break;
		case 124:
			//Windows V5
			printf("Can't load Windows V5 bitmaps\n");
			break;
		default:
			printf("Unknown bitmap format\n");
	}
	
	//Read the data
	int bytesPerRow = ((w*3+3)/4)*4 - (w*3%4);
	int size = bytesPerRow * h;
    char* image = new char[size];
	input.seekg(dataOffset, ios_base::beg);
	input.read(image, size);
    
    if(width != w || height != h){
        printf("width and height of file do not match that of texture\n");
        return;
    }
	
	//Get the data into the right format
    texture = new unsigned char[w*h*3];
	for(y=0; y<height; y++) {
		for(x=0; x<width; x++) {
			for(c=0; c<3; c++) {
				texture[3 * (width*y+x) + c] = image[bytesPerRow*y + 3*x + (2-c)];
			}
		}
	}
	
	input.close();
}


